package main

import (
	"fmt"
	"sync"
)

func main() {
	// ======================

	// 并发带来的问题，如果解锁一个不存在的锁，就会有panic的异常错误
	// 下面简单的例子演示了锁的问题，可以尝试更换锁的位置来看看结果
	// var m sync.Mutex
	// go func() {
	// 	m.Unlock()
	// }()
	// m.Lock()

	// ======================
	// 测试结果，如果在主线程中，没有出现阻塞的话，那么主线程内部的子线程是可以进行执行的
	// 如果子线程运行之后那么子线程跟主线程即将执行的代码块的话，会出现并发抢夺资源的问题
	// go func() {
	// 	for {
	// 		fmt.Println("是否。。。。。。")
	// 	}
	// }()
	// for {
	// 	fmt.Println("并发测试......")
	// }
	// 解决方案>>[1.可以考虑使用锁<互斥量 ：互斥锁，加锁的机制来处理>][2.可以使用channel来规定
	// channel执行的顺序][3.或者使用sleep等等其他耗时或者堵塞的操作来实现]
	// 关于并发抢夺资源的问题处理，可以考虑原子操作来保证资源的一致性，原子性等，
	// 如果是DB的操作可以考虑使用事务来处理资源的争抢问题
	// ======================

	// var ch = make(chan int, 10)
	// // 有缓存的通道是可以拓展G到cap(缓存大小),如果超过大小的话，是很危险的，如果写出的操作还没有执行执行
	// // 执行之前，通道内部的数据写入已经大于cap大小的话，会引发panic，所以通道的大小是不能超过cap的大小
	// for i := 0; i < cap(ch); i++ {
	// 	go func(i int) { ch <- i }(i)
	// }
	// for i := 0; i < cap(ch); i++ {
	// 	fmt.Println(i, ": ", <-ch)

	// }
	// ======================
	// 另一种控制G的退出 sync.WaitGroup
	var wg sync.WaitGroup
	var ch = make(chan int, 10)
	wg.Add(10) // 管理10个G<虚拟线程>
	for i := 0; i < cap(ch); i++ {
		go func(i int, wg *sync.WaitGroup) {
			defer wg.Done()
			ch <- i
		}(i, &wg)
	}
	// for v := range ch {
	// 	fmt.Println(v)
	// }
	fmt.Println()
	wg.Wait()

}
